/*
 * Copyright (c) 2020 hebeiyiliuba.com
 * All rights reserved.
 *
 */

package org.jeecg.modules.third.jg.report.freight.information.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.third.jg.report.freight.information.constant.HenanReportConstant;
import org.jeecg.modules.third.jg.report.freight.information.constant.HuaibeiReportConstant;
import org.jeecg.modules.third.jg.report.freight.information.constant.SdReportConstant;
import org.jeecg.modules.third.jg.report.freight.information.constant.SxReportConstant;
import org.jeecg.modules.third.jg.report.freight.information.constant.enums.ReportDocTypeEnum;
import org.jeecg.modules.third.jg.report.freight.information.dto.AppInfoDTO;
import org.jeecg.modules.third.jg.report.freight.information.model.ExchangeModel;
import org.jeecg.modules.third.jg.report.freight.information.model.R;
import org.jeecg.modules.third.jg.report.freight.information.model.Root;
import org.jeecg.modules.third.jg.report.freight.information.util.WebUtils;
import org.jeecg.modules.third.jg.report.freight.information.util.sm.SM2Util;
import org.jeecg.modules.third.jg.report.freight.information.util.sm.SM4Util;
import org.jeecg.modules.third.jg.report.freight.information.util.sm.Util;
import org.jeecg.modules.wlhy.hyconfig.entity.HyConfig;
import org.jeecg.modules.wlhy.utils.HyCfgUtil;
import org.jeecg.modules.wlhy.utils.HyConfigUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @Description: 河南平台上报服务
 * @author: duanlikao
 * @date: 2022年10月09日 10:58
 */
@Service
@Slf4j
public class HeNanReportPlatformService {

    @Resource
    private RedisUtil redisUtil;

    private String domainURL;

    private String username;

    private String password;

    private String debugSystem;

    private String appId;

    private String appSecurity;

    private String appSenderCode;

    private String appDebugSystem;

    public AppInfoDTO getAppInfo() {
        return AppInfoDTO.builder()
                .appId(this.appId)
                .appSecurity(this.appSecurity)
                .enterpriseSenderCode(this.appSenderCode)
                .debugSystem(this.appDebugSystem)
                .build();
    }

    public void setReportInfo(String reportPlatformDomain,
                              String username,
                              String password,
                              String publickey,
                              String appId,
                              String appSecurity,
                              String appSenderCode,
                              String appDebugSystem) {
        //联调状态的App需要设置debugSystem
        if ("0".equals(appDebugSystem)) {
            appDebugSystem = "debugSystem";
        }

        this.domainURL = reportPlatformDomain;
        this.username = username;
        this.password = password;
        this.debugSystem = "";
        this.appId = appId;
        this.appSecurity = appSecurity;
        this.appSenderCode = appSenderCode;
        this.appDebugSystem = appDebugSystem;
    }

    private String getLoginToken() throws Exception {

        if (StrUtil.isEmpty(this.domainURL) || StrUtil.isEmpty(this.username) || StrUtil.isEmpty(this.password)) {
            throw new JeecgBootException("河南上报服务参数配置错误,请联系管理员。");
        }

        log.info("{} - {} - {} - {}", this.domainURL, this.username, this.password, this.debugSystem);
        Object tokenObject = redisUtil.get(HenanReportConstant.API_REPORT_TOKEN_KEY);
        if (tokenObject != null) {
            return tokenObject.toString();
        }

        String getpublicKeyPost = HttpUtil.post(this.domainURL + HenanReportConstant.RSA_URL, "{}");
        log.info("河南监管获取公钥回执 <- {}", getpublicKeyPost);

        Map<String, Object> resultPublicKeyMap = JSON.parseObject(getpublicKeyPost, Map.class);
        String publicKey = (String) ((Map) resultPublicKeyMap.get("data")).get("publicKey");
        String encryptPassword = SM2Util.encrypt(publicKey, this.password);

        String url = this.domainURL + HenanReportConstant.AUTH_URL;

        Map<String, String> loginParam = new HashMap<>();
        loginParam.put("account", this.username);
        loginParam.put("passwd", encryptPassword);
        loginParam.put("publicRsa", publicKey);
        //登录申请令牌的参数systemCode: debugSystem不填写为正式环境
        if ("debugSystem".equals(this.debugSystem)) {
            loginParam.put("systemCode", this.debugSystem);
        }

        log.info("河南监管获取Token请求 -> {} {}", url, JSONUtil.toJsonStr(loginParam));
        String authResult = HttpUtil.post(url, JSONUtil.toJsonStr(loginParam));
        log.info("河南监管获取Token回执 <- {}", authResult);
        Map<String, Object> loginResultMap = JSON.parseObject(authResult, Map.class);
        String code = (String) loginResultMap.get("code");

        if (!code.equals("0")) {
            throw new Exception("token获取异常," + loginResultMap.get("message"));
        }

        redisUtil.set(HenanReportConstant.API_REPORT_TOKEN_KEY, authResult, HenanReportConstant.API_REPORT_TOKEN_KEY_EXPIRE);
        return authResult;
    }



    /**
     * 组装交换报文
     * @param reportDocTypeEnum 上报单据类型
     * @param jsonString 报文内容
     * @return
     */
    private Root messageAssembly(ReportDocTypeEnum reportDocTypeEnum ,String jsonString ) throws Exception {

        if(!ReportDocTypeEnum.isValid(reportDocTypeEnum.getCode()) || StringUtils.isEmpty(jsonString)){
            throw new JeecgBootException("上报单据类型异常");
        }
        String loginPost = getLoginToken();
        if(StringUtils.isEmpty(loginPost)){
            throw new JeecgBootException("监管平台token获取异常");
        }

        Map<String,Object> loginResultMap = JSON.parseObject(loginPost,Map.class);

        String token = (String) ((Map)loginResultMap.get("data")).get("token");
        String msgPublicKey = (String) ((Map)loginResultMap.get("data")).get("PUBLIC_KEY");

        //组装交换报文
        Root root = new Root();
        root.setMessageReferenceNumber(UUID.randomUUID().toString().replace("-", ""));
        root.setDocumentName(reportDocTypeEnum.getMsg());
        root.setDocumentVersionNumber("1.1");
        root.setRecipientCode("wlhymot");
        root.setSenderCode(this.username);
        root.setMessageSendingDateTime(
                DateUtils.dateToStringDateTime(new Date())
        );
        root.setIpcType(reportDocTypeEnum.getCode());
        root.setToken(token);
        root.setUserName(this.username);
        String key = null;
        try {
            String encrypt = null;
            //生成对称密钥
            key = SM4Util.generateKey();
            //使用对称密钥加密业务报文
            String encryptBase64 = SM4Util.encrypt_Ecb_Padding(key, jsonString);
            //使用sm2公用加密对称密钥
            encrypt = SM2Util.encrypt(msgPublicKey, key);
            root.setEncryptedCode(encrypt);
            root.setEncryptedContent(encryptBase64);
            return root;
        } catch (Exception e) {
            log.error("河南上报组装交换报文异常:{}" ,  e.getMessage());
        }

        return null;
    }

    /**
     * 发送上报
     * @param reportDocTypeEnum
     * @param jsonString
     */
    public String sendReport(ReportDocTypeEnum reportDocTypeEnum ,String jsonString) throws Exception {

        if (!HyCfgUtil.isUsed2("henan_report")){
            throw new JeecgBootException("河南上报服务暂未开启,请联系管理。");
        }

        String sendResult;
        try {
            Root exchangeModel = messageAssembly(reportDocTypeEnum, jsonString);
            if (exchangeModel != null) {
                //发送报文
                //如果配置了debugSystem，向联调环境发送请求
                String url = "debugSystem".equals(this.debugSystem) ?
                        this.domainURL + HenanReportConstant.TEST_SEND_URL : this.domainURL + HenanReportConstant.SEND_URL;

                log.info("河南上报报文请求 -> {}, {}", exchangeModel.getMessageReferenceNumber(), jsonString);
                sendResult = HttpUtil.post(url, JSONUtil.toJsonStr(exchangeModel));
                log.info("河南上报报文回执 <- {}", sendResult);
                if (StringUtils.isNotEmpty(sendResult)) {
                    R result = JSON.parseObject(sendResult, R.class);
                    //TOKEN 失效
                    if (2001 == result.getCode() || 2002 == result.getCode()) {
                        redisUtil.del(SxReportConstant.API_REPORT_TOKEN_KEY);
                    }
                    if (1001 == result.getCode()) {
                        return sendResult;
                    }
                }
            }
        } catch (Exception e) {
            log.error("河南上报报文异常:{}", e.getMessage());
            e.printStackTrace();
        }

        return StringUtils.EMPTY;
    }
}
